/**
 ***************************************************************************************************
 *
 * @file app_sec.c
 *
 * @brief Security request and response process.
 *
 * Copyright (C) Eker 2021
 *
 *
 ***************************************************************************************************
 */

/**
 ***************************************************************************************************
 * @addtogroup APP
 * @{
 ***************************************************************************************************
 */

/*
 * INCLUDE FILES
 ***************************************************************************************************
 */
#include "app.h"

#if (BLE_APP_SEC)

#define APP_LOG_DOMAIN      "sec"
#define APP_LOG_LEVEL       APP_LOG_LEVEL_SEC
#include "app_log.h"

/*
 * GLOBAL VARIABLES DEFINITION
 ***************************************************************************************************
 */
// Application Security Environment Structure
struct app_sec_env_tag app_sec_env;

/*
 * GLOBAL FUNCTIONS DEFINITION
 ***************************************************************************************************
 */
void app_sec_init()
{
    memset(&app_sec_env, 0, sizeof(app_sec_env));
#if (NVDS_SUPPORT)
    struct app_sec_conn_info_tag info;
    uint8_t length = sizeof(struct app_sec_conn_info_tag);
    uint8_t nvds_len = NVDS_TAG_BLE_LINK_KEY_LAST-NVDS_TAG_BLE_LINK_KEY_FIRST;

    app_sec_env.bonded = false;

    // Get bond status from NVDS
    for(int index =0; index <= nvds_len; index++)
    {
        length = sizeof(struct app_sec_conn_info_tag);
        memset(&info, 0, length);
        if (nvds_get(NVDS_TAG_BLE_LINK_KEY_FIRST+index, &length, (uint8_t *)&info) == NVDS_OK)
        {
            app_sec_env.bonded = true;
            break;
        }
    }
#endif
}

bool app_sec_get_bond_status_by_addr(bd_addr_t addr)
{
#if (NVDS_SUPPORT)
    struct app_sec_conn_info_tag info;
    uint8_t length = sizeof(struct app_sec_conn_info_tag);
    uint8_t nvds_len = NVDS_TAG_BLE_LINK_KEY_LAST-NVDS_TAG_BLE_LINK_KEY_FIRST;

    // Get bond status from NVDS
    for(int index =0; index <= nvds_len; index++)
    {
        length = sizeof(struct app_sec_conn_info_tag);
        memset(&info, 0, length);
        if (nvds_get(NVDS_TAG_BLE_LINK_KEY_FIRST+index, &length, (uint8_t *)&info) == NVDS_OK)
        {
            if (memcmp(&info.id_addr.addr, &addr, sizeof(bd_addr_t)) == 0)
            {
                return true;
            }
        }
    }
#endif
    return false;
}

bool app_sec_get_bond_status(void)
{
    return app_sec_env.bonded;
}

void app_sec_remove_bond(void)
{
#if (NVDS_SUPPORT)
    // Check if we are well bonded
    if (app_sec_env.bonded == true)
    {
        // Update the environment variable
        app_sec_env.bonded = false;

        uint8_t nvds_len = NVDS_TAG_BLE_LINK_KEY_LAST-NVDS_TAG_BLE_LINK_KEY_FIRST;

        for(int index =0; index <= nvds_len; index++)
        {
            nvds_del(NVDS_TAG_BLE_LINK_KEY_FIRST+index);
        }
    }
#if (BLE_APP_SEC_CON)
    memset(&app_sec_env, 0, sizeof(app_sec_env));
#endif
#endif

#if (BLE_APP_WHITE_LIST)
    appm_whl_clear();
#endif

#if (BLE_APP_PRIVACY)
    appm_privacy_clear();
#endif
}

void app_sec_send_security_req(uint8_t conidx)
{
    // Send security request
    struct gapc_security_cmd *cmd = KE_MSG_ALLOC(GAPC_SECURITY_CMD,
                                                 KE_BUILD_ID(TASK_GAPC, conidx),
                                                 TASK_APP,
                                                 gapc_security_cmd);

    cmd->operation = GAPC_SECURITY_REQ;
    cmd->auth      = GAP_AUTH_REQ_NO_MITM_BOND;

    // Send the message
    ke_msg_send(cmd);
}

void app_sec_encrypt_req(uint8_t conidx, bd_addr_t peer_addr)
{
    struct gapc_encrypt_cmd *cmd = KE_MSG_ALLOC(GAPC_ENCRYPT_CMD,
                                                KE_BUILD_ID(TASK_GAPC, conidx),
                                                TASK_APP,
                                                gapc_encrypt_cmd);

    cmd->operation = GAPC_ENCRYPT;
#if (NVDS_SUPPORT)
    struct app_sec_conn_info_tag info;
    uint8_t length = sizeof(struct app_sec_conn_info_tag);
    uint8_t nvds_len = NVDS_TAG_BLE_LINK_KEY_LAST-NVDS_TAG_BLE_LINK_KEY_FIRST;

    // Get bond status from NVDS
    for(int index =0; index <= nvds_len; index++)
    {
        length = sizeof(struct app_sec_conn_info_tag);
        memset(&info, 0, length);
        if (nvds_get(NVDS_TAG_BLE_LINK_KEY_FIRST+index, &length, (uint8_t *)&info) == NVDS_OK)
        {
            if (memcmp(&info.id_addr.addr, &peer_addr, sizeof(bd_addr_t)) == 0)
            {
                memcpy(&cmd->ltk, &info.ltk, sizeof(struct gapc_ltk));
                break;
            }
        }
    }
#endif
    
    // Send the message
    ke_msg_send(cmd);
}

void app_sec_bond_req(uint8_t conidx)
{
    struct gapc_bond_cmd *cmd = KE_MSG_ALLOC(GAPC_BOND_CMD,
                                             KE_BUILD_ID(TASK_GAPC, conidx), 
                                             TASK_APP,
                                             gapc_bond_cmd);

    cmd->operation = GAPC_BOND;
    // IO capabilities (@see gap_io_cap)
    cmd->pairing.iocap = GAP_IO_CAP_NO_INPUT_NO_OUTPUT;
    cmd->pairing.oob = GAP_OOB_AUTH_DATA_NOT_PRESENT;
    // Authentication (@see gap_auth)
    // Note in BT 4.1 the Auth Field is extended to include 'Key Notification' and
    // and 'Secure Connections'.
    cmd->pairing.auth = GAP_AUTH_REQ_NO_MITM_BOND;
    // Encryption key size (7 to 16)
    cmd->pairing.key_size = 16;
    // Initiator key distribution (@see gap_kdist)
    cmd->pairing.ikey_dist = GAP_KDIST_ENCKEY | GAP_KDIST_IDKEY;
    // Responder key distribution (@see gap_kdist)
    cmd->pairing.rkey_dist = GAP_KDIST_ENCKEY | GAP_KDIST_IDKEY;
    // Device security requirements (minimum security level). (@see gap_sec_req)
    cmd->pairing.sec_req = GAP_NO_SEC;
    // Send the message
    ke_msg_send(cmd);
}

int app_sec_gapc_disconnect_ind_handler(ke_msg_id_t const msgid,
                                        void *param,
                                        ke_task_id_t const dest_id,
                                        ke_task_id_t const src_id)
{
    uint8_t conidx = KE_IDX_GET(src_id);

    if (conidx < BLE_CONNECTION_MAX) 
    {
    #if (BLE_APP_SEC_CON)
        app_sec_env.sec_con_enabled[conidx] = false;
    #endif
        app_sec_env.con_bonded[conidx] = false;
    }
    return (KE_MSG_CONSUMED);
}

/*
 * MESSAGE HANDLERS
 ***************************************************************************************************
 */
static int app_sec_msg_dflt_handler(ke_msg_id_t const msgid,
                                    void *param,
                                    ke_task_id_t const dest_id,
                                    ke_task_id_t const src_id)
{
    return (KE_MSG_CONSUMED);
}

/**
 ***************************************************************************************************
 * @brief GAPC_BOND_REQ_IND handler
 *
 * @param[in] msgid  : Id of the message received.
 * @param[in] param  : Pointer to the parameters of the message.
 * @param[in] dest_id: ID of the receiving task instance (TASK_GAP).
 * @param[in] src_id : ID of the sending task instance.
 *
 * @return If the message was consumed or not.
 ***************************************************************************************************
 */
static int gapc_bond_req_ind_handler(ke_msg_id_t const msgid,
                                     struct gapc_bond_req_ind const *param,
                                     ke_task_id_t const dest_id,
                                     ke_task_id_t const src_id)
{
    uint8_t conidx = KE_IDX_GET(src_id);

    // Prepare the GAPC_BOND_CFM message
    struct gapc_bond_cfm *cfm = KE_MSG_ALLOC(GAPC_BOND_CFM, src_id, TASK_APP, gapc_bond_cfm);

    switch (param->request)
    {
        case (GAPC_PAIRING_REQ):
        {
            LOG_DBG("GAPC_PAIRING_REQ");
            cfm->request = GAPC_PAIRING_RSP;

            cfm->accept  = false;

            // Check if we are already bonded (Only one bonded connection is supported)
            if (!app_sec_env.con_bonded[conidx])
            {
                cfm->accept  = true;

                cfm->data.pairing_feat.auth      = GAP_AUTH_REQ_NO_MITM_BOND;

            #if (BLE_APP_HT)
                cfm->data.pairing_feat.iocap     = GAP_IO_CAP_DISPLAY_ONLY;
            #else
                cfm->data.pairing_feat.iocap     = GAP_IO_CAP_NO_INPUT_NO_OUTPUT;
            #endif

                cfm->data.pairing_feat.key_size  = 16;
                cfm->data.pairing_feat.oob       = GAP_OOB_AUTH_DATA_NOT_PRESENT;
                cfm->data.pairing_feat.sec_req   = GAP_NO_SEC;

            #if (BLE_APP_PRIVACY)
                cfm->data.pairing_feat.ikey_dist = GAP_KDIST_ENCKEY | GAP_KDIST_IDKEY;
                cfm->data.pairing_feat.rkey_dist = GAP_KDIST_ENCKEY | GAP_KDIST_IDKEY;
            #else
                cfm->data.pairing_feat.ikey_dist = GAP_KDIST_IDKEY;
                cfm->data.pairing_feat.rkey_dist = GAP_KDIST_ENCKEY;
            #endif
            }
        } break;

        case (GAPC_LTK_EXCH):
        {
            LOG_DBG("GAPC_LTK_EXCH");
            // Counter
            uint8_t counter;

            cfm->accept  = true;
            cfm->request = GAPC_LTK_EXCH;

            // Generate all the values
            cfm->data.ltk.ediv = (uint16_t)co_rand_word();

            for (counter = 0; counter < RAND_NB_LEN; counter++)
            {
                cfm->data.ltk.ltk.key[counter] = (uint8_t)co_rand_word();
                cfm->data.ltk.randnb.nb[counter] = (uint8_t)co_rand_word();
            }

            for (counter = RAND_NB_LEN; counter < KEY_LEN; counter++)
            {
                cfm->data.ltk.ltk.key[counter] = (uint8_t)co_rand_word();
            }

            LOG_DBG_ARRAY_EX("LTK", &cfm->data.ltk,  sizeof(struct gapc_ltk));
            memcpy(&app_sec_env.info[conidx].ltk, &cfm->data.ltk, sizeof(struct gapc_ltk));
            memcpy(&app_sec_env.info[conidx].ltk.randnb.nb[0], &cfm->data.ltk.randnb.nb[0], RAND_NB_LEN);
            app_sec_env.info[conidx].ltk.ediv = cfm->data.ltk.ediv;
        } break;


        case (GAPC_IRK_EXCH):
        {
            LOG_DBG("GAPC_IRK_EXCH");
            cfm->accept  = true;
            cfm->request = GAPC_IRK_EXCH;

            // Load IRK
            memcpy(cfm->data.irk.irk.key, app_env.loc_irk, KEY_LEN);

            // load device address
        #if (NVDS_SUPPORT)
            uint8_t addr_len = BD_ADDR_LEN;
            if (nvds_get(NVDS_TAG_BD_ADDRESS, &addr_len, cfm->data.irk.addr.addr.addr) != NVDS_OK)
        #endif
            {
                bd_addr_t loc_addr;
                str_2_bdaddr(LOCAL_DEFAULT_ADDR, &loc_addr);
                memcpy(cfm->data.irk.addr.addr.addr, &loc_addr, BD_ADDR_LEN);
            }
            cfm->data.irk.addr.addr_type = (cfm->data.irk.addr.addr.addr[5] & 0xC0) ? ADDR_RAND : ADDR_PUBLIC;
        } break;

        case (GAPC_TK_EXCH):
        {
            LOG_DBG("GAPC_TK_EXCH");
            // Generate a PIN Code - (Between 100000 and 999999)
            uint32_t pin_code = (100000 + (co_rand_word()%900000));

            cfm->accept  = true;
            cfm->request = GAPC_TK_EXCH;

            // Set the TK value
            memset(cfm->data.tk.key, 0, KEY_LEN);

            cfm->data.tk.key[0] = (uint8_t)((pin_code & 0x000000FF) >>  0);
            cfm->data.tk.key[1] = (uint8_t)((pin_code & 0x0000FF00) >>  8);
            cfm->data.tk.key[2] = (uint8_t)((pin_code & 0x00FF0000) >> 16);
            cfm->data.tk.key[3] = (uint8_t)((pin_code & 0xFF000000) >> 24);
        } break;

        case (GAPC_NC_EXCH):
        {
            LOG_DBG("GAPC_NC_EXCH");
            cfm->accept  = true;
            cfm->request = GAPC_NC_EXCH;
        } break;

        default:
        {
            ASSERT_ERR(0);
        } break;
    }

    // Send the message
    ke_msg_send(cfm);

    return (KE_MSG_CONSUMED);
}

/**
 ***************************************************************************************************
 * @brief GAPC_BOND_IND handler
 *
 * @param[in] msgid  : Id of the message received.
 * @param[in] param  : Pointer to the parameters of the message.
 * @param[in] dest_id: ID of the receiving task instance (TASK_GAP).
 * @param[in] src_id : ID of the sending task instance.
 *
 * @return If the message was consumed or not.
 ***************************************************************************************************
 */
static int gapc_bond_ind_handler(ke_msg_id_t const msgid,
                                 struct gapc_bond_ind const *param,
                                 ke_task_id_t const dest_id,
                                 ke_task_id_t const src_id)
{
    uint8_t conidx = KE_IDX_GET(src_id);

    switch (param->info)
    {
        case (GAPC_PAIRING_SUCCEED):
        {
            LOG_DBG("GAPC_PAIRING_SUCCEED");
            // Update the bonding status in the environment
            app_sec_env.bonded = true;
            app_sec_env.con_bonded[conidx] = true;

        #if (NVDS_SUPPORT)
            struct app_sec_conn_info_tag info;
            uint8_t length = sizeof(struct app_sec_conn_info_tag);
            uint8_t nvds_len = NVDS_TAG_BLE_LINK_KEY_LAST-NVDS_TAG_BLE_LINK_KEY_FIRST;

            memcpy(&app_sec_env.info[conidx].id_addr, (uint8_t *)gapc_get_bdaddr(conidx, SMPC_INFO_PEER), sizeof(struct gap_bdaddr));
            LOG_DBG_ARRAY_EX("id_addr", &app_sec_env.info[conidx].id_addr, sizeof(struct gap_bdaddr));
            LOG_DBG("ediv = %x", app_sec_env.info[conidx].ltk.ediv);
            LOG_DBG_ARRAY_EX("nb", &app_sec_env.info[conidx].ltk.randnb.nb[0], GAP_RAND_NB_LEN);

            // Get bond status from NVDS
            int index = 0;
            for(index =0; index <= nvds_len; index++)
            {
                length = sizeof(struct app_sec_conn_info_tag);
                memset(&info, 0, length);
                if (nvds_get(NVDS_TAG_BLE_LINK_KEY_FIRST+index, &length, (uint8_t *)&info) != NVDS_OK)
                {
                    length = sizeof(struct app_sec_conn_info_tag);
                    uint8_t ret = nvds_put(NVDS_TAG_BLE_LINK_KEY_FIRST+index, length, (uint8_t*)&app_sec_env.info[conidx]);
                    break;
                }
                else
                {
                    LOG_DBG("get, index = %d, ediv = %x", index, info.ltk.ediv);
                    LOG_DBG_ARRAY_EX("nb", &info.ltk.randnb.nb[0], GAP_RAND_NB_LEN);
                }
            }
            if (index > nvds_len)
            {
                nvds_del(NVDS_TAG_BLE_LINK_KEY_FIRST);
                length = sizeof(struct app_sec_conn_info_tag);
                uint8_t ret = nvds_put(NVDS_TAG_BLE_LINK_KEY_FIRST, length, (uint8_t*)&app_sec_env.info[conidx]);
            }
        #endif

        #if (BLE_APP_WHITE_LIST==1 && BLE_APP_PRIVACY==0)
            appm_whl_add_device((uint8_t *)gapc_get_bdaddr(0, SMPC_INFO_PEER));
        #endif

            // SMP paired, to do something here
            
        } break;

        case (GAPC_REPEATED_ATTEMPT):
        {
            LOG_DBG("GAPC_REPEATED_ATTEMPT");
            appm_disconnect(KE_IDX_GET(src_id), CO_ERROR_REMOTE_USER_TERM_CON);
        } break;

        case (GAPC_IRK_EXCH):
        {
            LOG_DBG("GAPC_IRK_EXCH");
        #if (NVDS_SUPPORT)
            memcpy(&app_sec_env.info[conidx].irk, (uint8_t *)&param->data.irk, sizeof(struct gapc_irk));
        #endif
            LOG_DBG_ARRAY_EX("New IRK", (uint8_t *)&param->data.irk, KEY_LEN);
            LOG_DBG_ARRAY_EX("Local IRK", app_env.loc_irk, KEY_LEN);

        #if (BLE_APP_WHITE_LIST)
            appm_whl_add_device((uint8_t *)&param->data.irk.addr);
        #endif
        #if (BLE_APP_PRIVACY)
            struct gap_ral_dev_info device;
            memcpy(&device.addr, &param->data.irk.addr, sizeof(struct gap_bdaddr));
            device.priv_mode = 1;
            memcpy(device.peer_irk, param->data.irk.irk.key, GAP_KEY_LEN);
            memcpy(device.local_irk, app_env.loc_irk, GAP_KEY_LEN);
            appm_privacy_add_device((uint8_t*)&device);
        #endif
        } break;

        case (GAPC_PAIRING_FAILED):
        {
            LOG_DBG("GAPC_PAIRING_FAILED");
            //app_sec_send_security_req(0);
            LOG_DBG("pairing failed reason = %x", param->data.reason);
        } break;

        // In Secure Connections we get BOND_IND with SMPC calculated LTK
        case (GAPC_LTK_EXCH):
        {
            LOG_DBG("GAPC_LTK_EXCH");
        #if (BLE_APP_SEC_CON)
            //del the if, when master pair, edir & nb = 0
            //if (app_sec_env.sec_con_enabled[conidx] == true)
            {
            #if (NVDS_SUPPORT)
                memcpy(&app_sec_env.info[conidx].ltk, (uint8_t *)&param->data.ltk, sizeof(struct gapc_ltk));
            #endif
            }
        #endif
        }
        break;

        default:
        {
            ASSERT_ERR(0);
        } break;
    }

    return (KE_MSG_CONSUMED);
}

/**
 ***************************************************************************************************
 * @brief GAPC_BOND_CFM handler
 *
 * @param[in] msgid  : Id of the message received.
 * @param[in] param  : Pointer to the parameters of the message.
 * @param[in] dest_id: ID of the receiving task instance (TASK_GAP).
 * @param[in] src_id : ID of the sending task instance.
 *
 * @return If the message was consumed or not.
 ***************************************************************************************************
 */
static int gapc_bond_cfm_handler(ke_msg_id_t const msgid,
                                 struct gapc_bond_cfm const *param,
                                 ke_task_id_t const dest_id,
                                 ke_task_id_t const src_id)
{
    LOG_DBG("request = %x, accept = %x", param->request, param->accept);
    //union gapc_bond_cfm_data data;
    return (KE_MSG_CONSUMED);
}

/**
 ***************************************************************************************************
 * @brief GAPC_ENCRYPT_REQ_IND handler
 *
 * @param[in] msgid  : Id of the message received.
 * @param[in] param  : Pointer to the parameters of the message.
 * @param[in] dest_id: ID of the receiving task instance (TASK_GAP).
 * @param[in] src_id : ID of the sending task instance.
 *
 * @return If the message was consumed or not.
 ***************************************************************************************************
 */
static int gapc_encrypt_req_ind_handler(ke_msg_id_t const msgid,
                                        struct gapc_encrypt_req_ind const *param,
                                        ke_task_id_t const dest_id,
                                        ke_task_id_t const src_id)
{
    uint8_t conidx = KE_IDX_GET(src_id);

    // Prepare the GAPC_ENCRYPT_CFM message
    struct gapc_encrypt_cfm *cfm = KE_MSG_ALLOC(GAPC_ENCRYPT_CFM,
                                                src_id,
                                                TASK_APP,
                                                gapc_encrypt_cfm);

    cfm->found = false;
    if (app_sec_env.con_bonded[conidx])
    {
        if ((param->ediv == app_sec_env.info[conidx].ltk.ediv) &&
            !memcmp(&param->rand_nb.nb[0], &app_sec_env.info[conidx].ltk.randnb.nb[0], sizeof(struct rand_nb)))
            {
                cfm->found    = true;
                cfm->key_size = 16;
                memcpy(&cfm->ltk, &app_sec_env.info[conidx].ltk.ltk, sizeof(struct gap_sec_key));
            }
    }
    else if (app_sec_env.bonded)
    {
    #if (NVDS_SUPPORT)
        struct app_sec_conn_info_tag info;
        uint8_t length = sizeof(struct app_sec_conn_info_tag);
        uint8_t index = 0;
        uint8_t nvds_len = NVDS_TAG_BLE_LINK_KEY_LAST-NVDS_TAG_BLE_LINK_KEY_FIRST;

        LOG_DBG("ediv = %x", param->ediv);
        LOG_DBG_ARRAY_EX("nb", &param->rand_nb.nb[0], GAP_RAND_NB_LEN);

        for(index =0; index <= nvds_len; index++)
        {
            length = sizeof(struct app_sec_conn_info_tag);
            memset(&info, 0, length);
            if (nvds_get(NVDS_TAG_BLE_LINK_KEY_FIRST+index, &length, (uint8_t *)&info) == NVDS_OK)
            {
                if ((param->ediv == info.ltk.ediv) &&
                    !memcmp(&param->rand_nb.nb[0], &info.ltk.randnb.nb[0], sizeof(struct rand_nb)))
                {
                    cfm->found    = true;
                    cfm->key_size = 16;
                    memcpy(&cfm->ltk, &info.ltk.ltk, sizeof(struct gap_sec_key));
                    break;
                }
                else
                {
                    LOG_DBG("OK, index = %d, ediv = %x", index, info.ltk.ediv);
                    LOG_DBG_ARRAY_EX("nb", &info.ltk.randnb.nb[0], GAP_RAND_NB_LEN);
                }
            }
            else
            {
                LOG_DBG("Failed, index = %d, ediv = %x", index, info.ltk.ediv);
                LOG_DBG_ARRAY_EX("nb", &info.ltk.randnb.nb[0], GAP_RAND_NB_LEN);
            }
        }
    #endif
    }
    else
    {
        LOG_ERR("PIN or key missing");
    }

    // Send the message
    ke_msg_send(cfm);

    return (KE_MSG_CONSUMED);
}

/**
 ***************************************************************************************************
 * @brief GAPC_ENCRYPT_IND handler
 *        This message occur when reconnected
 *
 * @param[in] msgid  : Id of the message received.
 * @param[in] param  : Pointer to the parameters of the message.
 * @param[in] dest_id: ID of the receiving task instance (TASK_GAP).
 * @param[in] src_id : ID of the sending task instance.
 *
 * @return If the message was consumed or not.
 ***************************************************************************************************
 */
static int gapc_encrypt_ind_handler(ke_msg_id_t const msgid,
                                    struct gapc_encrypt_ind const *param,
                                    ke_task_id_t const dest_id,
                                    ke_task_id_t const src_id)
{
    // SMP encrypted, to do something here
    

    return (KE_MSG_CONSUMED);
}

/*
 * LOCAL VARIABLE DEFINITIONS
 ***************************************************************************************************
 */
// Default state handlers definition
const struct ke_msg_handler app_sec_msg_handler_list[] =
{
    // Note: first message is latest message checked by kernel so default is put on top.
    {KE_MSG_DEFAULT_HANDLER,  (ke_msg_func_t)app_sec_msg_dflt_handler},

    {GAPC_BOND_REQ_IND,       (ke_msg_func_t)gapc_bond_req_ind_handler},
    {GAPC_BOND_IND,           (ke_msg_func_t)gapc_bond_ind_handler},
    {GAPC_BOND_CFM,           (ke_msg_func_t)gapc_bond_cfm_handler},

    {GAPC_ENCRYPT_REQ_IND,    (ke_msg_func_t)gapc_encrypt_req_ind_handler},
    {GAPC_ENCRYPT_IND,        (ke_msg_func_t)gapc_encrypt_ind_handler},
};

const struct app_subtask_handlers app_sec_handlers = {&app_sec_msg_handler_list[0], ARRAY_LEN(app_sec_msg_handler_list)};

#else //(BLE_APP_SEC)

bool app_sec_get_bond_status(void)
{
    return false;
}

#endif //(BLE_APP_SEC)

/// @} APP
